﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;

namespace KATS_Client.Client
{
    /// <summary>
    /// This is the data that represents a queued action
    /// </summary>
    public class FileActionData
    {

        #region Instance Level Variables
        /// <summary>
        /// The type of action this represents
        /// </summary>
        private ActionTypes actionType;
        /// <summary>
        /// The initial object location
        /// </summary>
        private FileSystemObject location;
        /// <summary>
        /// The new object location
        /// </summary>
        private FileSystemObject newLocation;
        /// <summary>
        /// The time this action can be processed from
        /// </summary>
        private DateTime processTime = DateTime.Now; // generally auto process

        #endregion

        #region Properties
        /// <summary>
        /// The type of action this represents
        /// </summary>
        public ActionTypes ActionType
        {
            get { return actionType; }
        }
        /// <summary>
        /// The initial object location
        /// </summary>
        public FileSystemObject Location
        {
            get { return location; }
        }
        /// <summary>
        /// The new object location
        /// </summary>
        public FileSystemObject NewLocation
        {
            get { return newLocation; }
        }
        /// <summary>
        /// The time this action can be processed from
        /// </summary>
        public DateTime ProcessTime
        {
            get { return processTime; }
        }

        /// <summary>
        /// Does this file action involve the server?
        /// </summary>
        public bool RequiresServer
        {
            get
            {
                if (Location.IsRemote)
                    return true;
                if (NewLocation != null && NewLocation.IsRemote)
                    return true;
                return false;
            }
        }
        #endregion


        #region Constructors
        /// <summary>
        /// Create this file action
        /// </summary>
        /// <param name="ActionType">The type of action to do</param>
        /// <param name="InitialLocation">The starting location [local or remote]</param>
        /// <param name="Location">The location of the target</param>
        /// <param name="NewLocation">The new location of the target</param>
        /// <param name="processTime">The time this can be processed from</param>
        public FileActionData(ActionTypes ActionType, FileSystemObject Location, FileSystemObject NewLocation, DateTime processTime)
        {
            this.actionType = ActionType;
            this.location = Location;
            this.newLocation = NewLocation;
            this.processTime = processTime;
            RemoveSameFileEvent();
        }

        /// <summary>
        /// Create this file action
        /// </summary>
        /// <param name="ActionType">The type of action to do</param>
        /// <param name="InitialLocation">The starting location [local or remote]</param>
        /// <param name="Location">The location of the target</param>
        /// <param name="NewLocation">The new location of the target</param>
        public FileActionData(ActionTypes ActionType, FileSystemObject Location, FileSystemObject NewLocation)
        {
            this.actionType = ActionType;
            this.location = Location;
            this.newLocation = NewLocation;
            RemoveSameFileEvent();
        }

        /// <summary>
        /// Create this file action
        /// </summary>
        /// <param name="ActionType">The type of action to do</param>
        /// <param name="InitialLocation">The starting location [local or remote]</param>
        /// <param name="Location">The location of the target</param>
        public FileActionData(ActionTypes ActionType, FileSystemObject Location)
        {
            this.actionType = ActionType;
            this.location = Location;
            RemoveSameFileEvent();
        }

        /// <summary>
        /// Create this file action from one saved in xml
        /// </summary>
        /// <param name="SavedData">The saved data</param>
        public FileActionData(XElement SavedData)
        {
            this.actionType = (ActionTypes)Enum.Parse(typeof(ActionTypes), SavedData.Element("ActionType").Value, true);
            this.location = new FileSystemObject(SavedData.Element("Location").Element("FileSystemObject"));

            // special as the new location field may be empty
            XElement NewLocationXML = SavedData.Element("NewLocation");
            if (NewLocationXML.HasElements)
            {
                this.newLocation = new FileSystemObject(NewLocationXML.Element("FileSystemObject"));
            }
            else
            {
                this.newLocation = null;
            }
            this.processTime = DateTime.Parse(SavedData.Element("ProcessTime").Value);
        }

        #endregion

        /// <summary>
        /// Add so many seconds to the performing delay
        /// </summary>
        /// <param name="x"></param>
        public void WaitSeconds(int x)
        {
            this.processTime = this.processTime.AddSeconds(x);
        }

        /// <summary>
        /// Check all the file events, and remove any the same as this one
        /// </summary>
        private void RemoveSameFileEvent()
        {
            int i = 0;
            bool found = false;
            lock (FileActionsQueue.QueuedActions)
            {
                for (i = 0; i < FileActionsQueue.QueuedActions.Count; i++)
                {
                    FileActionData fad = FileActionsQueue.QueuedActions[i];
                    if (fad.Equals(this))
                    {
                        // therefore this event is already queued
                        // remove the original from the list
                        found = true;
                        break;
                    }
                }
            }
            if (found)
                FileActionsQueue.RemoveAt(i);
        }


        #region Overrode Object functions
        /// <summary>
        /// The equals function
        /// </summary>
        /// <param name="obj">The object to compare to</param>
        /// <returns>If they are equal or not</returns>
        public override bool Equals(object obj)
        {
            if (obj == null)
                return false;
            // no need to cast as both objects have ToString methodes
            return this.ToString() == obj.ToString();
        }

        /// <summary>
        /// Get a string representing this objects
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            string newlocation;
            if (this.NewLocation == null)
                newlocation = "[not set]";
            else
                newlocation = this.NewLocation.ToString();

            return string.Format("FileActionData: {0} {1} {2}", this.ActionType, this.Location.ToString(), newlocation);
        }

        /// <summary>
        /// Get the hash code for this object
        /// </summary>
        /// <returns>The hashcode</returns>
        public override int GetHashCode()
        {
            return this.ToString().GetHashCode();
        }

        #endregion

        /// <summary>
        /// Get the xml that represents this file action
        /// </summary>
        /// <returns>The xml element for this file action</returns>
        public XElement ToXML()
        {
            // special code, as the new location field may be null
            XElement newLocation;
            if (this.newLocation == null)
            {
                newLocation = new XElement("NewLocation");
            }
            else
            {
                newLocation = new XElement("NewLocation", this.newLocation.ToXML());
            }

            XElement e = new XElement("FileAction",
                new XElement("ActionType", this.actionType.ToString()),
                new XElement("Location", this.location.ToXML()),
                newLocation,
                new XElement("ProcessTime", this.processTime.ToString())
                );
            return e;
        }
    }
}
